package aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 用于记录日志的工具类（通知类）
 * @Aspect 注解表名当前类是一个通知类
 *      @Before:表明当前方法是前置通知方法
 *      @After：表明当前方法是后置通知方法
 *      @AfterReturning：表名当前方法是最终通知方法
 *      @AfterThrowing：表名当前方法是异常通知方法
 *      @Around：表名当前方法是环绕通知方法
 *      以上五个注解的value值为定义的切点表达式，如下
 *      @Before("pt1()")
 *      注意“（）”不可以省略，不然会报错
 *
 */
@Component
@Aspect
public class Logger {

    /**
     * 使用@Pointcut注解配置切入点表达式
     * 类似我们在bean.xml中配置的
     * <aop:pointcut id="pt1" expression="execution(* *..*.*(..))"/>
     */
    @Pointcut("execution(* service.impl.*.*(..))")
    private void pt1(){}

    /**
     * 用于打印日志信息，计划让其在切入点方法执行之前执行
     */
    @Before("pt1()")
    public void printLogBefore(){
        System.out.println("前置日志打印");
    }

    /**
     * 用于打印日志信息，计划让其在切入点方法执行之后执行
     */
    @After("pt1()")
    public void printLogAfter(){
        System.out.println("后置日志打印");
    }

    /**
     * 用于打印日志信息，计划让其在切入点方法执行结束后执行
     * 类似自己写的动态代理中的try-catch-finally中的finally
     */
    @AfterReturning("pt1()")
    public void printLogReturn(){
        System.out.println("最终日志打印");
    }

    /**
     * 用于打印日志信息，计划让其在切入点方法执行异常后执行
     */
    @AfterThrowing("pt1()")
    public void printLogThrow(){
        System.out.println("异常日志打印");
    }

    /**
     * 环绕通知
     */
    @Around("pt1()")
    public Object printLogAround(ProceedingJoinPoint proceedingJoinPoint){
        Object retValue = null;
        try {
            System.out.println("环绕通知-前置通知执行");
            //获取参数
            Object[] args = proceedingJoinPoint.getArgs();
            //执行切点方法
            retValue = proceedingJoinPoint.proceed(args);
            System.out.println("环绕通知-后置通知执行");
            return retValue;
            /**
             * 注意：此处不可以用Exception来捕获 他捕获不住
             * 因为proceedingJoinPoint.proceed(args);
             * 抛出的是Throwable
             */

        }catch (Throwable throwable){
            System.out.println("环绕通知-异常通知执行");
            throw new RuntimeException(throwable);
        }finally {
            System.out.println("环绕通知-最终通知执行");
        }
    }
}
